#include "AuctionManager.h"
#include "TeamManager.h"
#include "PlayerManager.h"
#include "User.h"
#include "ZStream.h"
#include "ServiceProvider.h"
#include "Player.h"
#include "PlayerFunctors.h"

#include <algorithm>
#include <cassert>

struct EqualBet
{
	EqualBet(const Player* const i_player) : m_player(i_player) {}
	bool operator()(const AuctionManager::Bet& i_bet)
	{
		return m_player == i_bet.m_player;
	}

	const Player* m_player;
};

AuctionManager::AuctionManager(ServiceProvider* i_sp) : m_sp(i_sp)
{
	assert(m_sp);
}

bool AuctionManager::Bidding(const Bet& i_bet)
{
	Bet::BetCollectionIt it = std::find_if(m_bets.begin(), m_bets.end(), EqualBet(i_bet.m_player));

	if(it == m_bets.end())
	{
		if(static_cast<int>(i_bet.m_bid) < i_bet.m_player->BuyValue() || static_cast<int>(i_bet.m_bid) > i_bet.m_team->GetBudget())
			return false;

		m_bets.push_back(i_bet);
		return true;
	}

	Bet& old_bet = (*it);

	if(i_bet.m_bid > old_bet.m_bid)
	{
		old_bet.m_bid = i_bet.m_bid;
		old_bet.m_team = i_bet.m_team;
		return true;
	}

	return false;
}

void AuctionManager::Clear()
{
	m_bets.clear();
	m_marketPlayers.clear();
}

void AuctionManager::CreateNewMarket(const size_t i_numberOfNewPlayers)
{
	m_marketPlayers = m_sp->GetPlayerMgr().GetFreePlayers(i_numberOfNewPlayers);
	std::random_shuffle(m_marketPlayers.begin(), m_marketPlayers.end());

	m_marketPlayers.erase(m_marketPlayers.begin() + i_numberOfNewPlayers, m_marketPlayers.end());
	std::sort(m_marketPlayers.begin(), m_marketPlayers.end(), PlayerBuyChoose);
}

void AuctionManager::Dispatch(const bool i_doNotPrompt)
{
	if(m_bets.empty())
		return;

	Bet::BetCollectionIt it = m_bets.begin();
	
	if(!i_doNotPrompt)
	{
		std::cout << "\n EVENTI MERCATO:\n";
	}

	const PlayerVec& freePlayers = m_sp->GetPlayerMgr().GetFreePlayers();
	for(it; it != m_bets.end(); ++it)
	{
		Bet& bet = (*it);

		if(std::find(freePlayers.begin(), freePlayers.end(), bet.m_player) != freePlayers.end())
		{
			bet.m_team->BuyPlayer(bet.m_player, bet.m_bid);
			if(!i_doNotPrompt)
			{
				std::cout << " ! " << bet.m_team->GetName() << " ha comprato " << bet.m_player->GetName() << " per " << bet.m_bid << " Banane!.\n";
			}
		}
	}

	if(!i_doNotPrompt)
	{
		std::cout << "\n";
	}

	m_bets.clear();
}

ZStream& AuctionManager::Serialize(ZStream& o_stream)
{
	o_stream.WriteOpenTag("Auctions");

	o_stream.WriteAttribute("BetNums", m_bets.size());

	for(size_t i = 0; i < m_bets.size(); ++i)
	{
		o_stream.WriteOpenTag("Entry");
		o_stream.WriteAttribute("PlayerID", m_bets[i].m_player->GetId());
		o_stream.WriteAttribute("TeamID", m_bets[i].m_team->GetID());
		o_stream.WriteAttribute("Bid", m_bets[i].m_bid);
		o_stream.WriteCloseTag("Entry");
	}

	o_stream.WriteCloseTag("Auctions");

	return o_stream;
}

ZStream& AuctionManager::Deserialize(ZStream& i_stream)
{
	m_bets.clear();

	i_stream.SkipLine();

	size_t betsNum;
	i_stream.ReadAttribute(betsNum);

	for(size_t i = 0; i < betsNum; ++i)
	{
		Bet bet;
		size_t playerID, teamID;

		i_stream.SkipLine();
		i_stream.ReadAttribute(playerID);
		i_stream.ReadAttribute(teamID);

		bet.m_player = m_sp->GetPlayerMgr().GetPlayerFromID(playerID);
		bet.m_team = m_sp->GetTeamMgr().GetTeamFromID(teamID);

		i_stream.ReadAttribute(bet.m_bid);
		i_stream.SkipLine();
	}

	i_stream.SkipLine();

	return i_stream;
}